/** @file cam-linux32.c
 * Implementiert (bzw simuliert) die Kamera-Schnittstelle auf einem 
 * 32-bit Linux System
 * 
 * @author Daniel Kummer, Sebastian Kummer
 * @date Donnerstag, Dezember 12, 2007
 * @version 1.0
 */

#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <linux/ioctl.h>
#include <errno.h>
#include <unistd.h>
#include <getopt.h>
#include <string.h>
#include <strings.h>

#include "lcv-config.h"
#include "cam.h"
#include "cam-reg-config.h"
#include "log.h"
#include "bmp.h"


/**
 *  Kamera Register initialisieren
 */
void lcv_cam_reg_init();

/**
 * Kamera Register inizialisiert
 */
unsigned char cam_reg_initialized = FALSE;

/** 
 * Array mit Kameraregistern 
 */
unsigned short cam_reg_values[sizeof(cam_reg_config) / sizeof(*cam_reg_config)];

lcv_picture lcv_capture_frame(const char* filename)
{
	unsigned short value;
	unsigned short width, height;
	lcv_picture res_pic = lcv_read_bmp(filename);
	char * error_msg;
	
	width  = lcv_config_read(REG_WINDOW_WIDTH);
	height = lcv_config_read(REG_WINDOW_HEIGHT);
	
	/*
	printf("width: %u\n", width);
	printf("col_start: %u\n", lcv_config_read(REG_COLUMN_START));
	printf("width default: %u\n", cam_reg_config[REG_WINDOW_WIDTH].default_val);
	printf("width max: %u\n", cam_reg_config[REG_WINDOW_WIDTH].max_val);
	*/
		
	if (width > cam_reg_config[REG_WINDOW_WIDTH].max_val) {
		error_msg = "The captured picture extends the maximal possible window width";	
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1);
	}
	
	if (height > cam_reg_config[REG_WINDOW_HEIGHT].max_val) {
		error_msg = "The captured picture extends the maximal possible window height";	
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1);
	}
	
	value = lcv_config_read(REG_WINDOW_HEIGHT);
	if (value != res_pic.height) {
		error_msg = "The captured picture does not have the same height as it is defined in the cam-register";
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1);
	}	
	
	value = lcv_config_read(REG_WINDOW_WIDTH);
	if (value != res_pic.width) {
		error_msg = "The captured picture does not have the same width as it is defined in the cam-register";
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1);
	}
	
	return res_pic;
}

lcv_picture lcv_capture_region(const unsigned short start_x, const unsigned short start_y, const unsigned short width, unsigned short height, const char * filename)
{
	char * error_msg;
	lcv_picture res_pic = lcv_read_bmp(filename);
	unsigned short nWidth, nHeight, nStart_x, nStart_y;
	
	/* Function is not yet fully implemented */
	error_msg = "Function not implemented";
	printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
	lcv_log_error(error_msg, __FUNCTION__);
	exit(-1);
	
	
	nWidth   = width;
	nHeight  = height;
	nStart_x = start_x;
	nStart_y = start_y;
	
	/* Auf legale Werte prüfen , Korrektur auf maximal mögliche Fenstergrösse */
	if (nStart_x < cam_reg_config[REG_COLUMN_START].min_val) {
		error_msg = "The start_x variable value (%u) is smaller than the minimal legal value: %u", nStart_x , cam_reg_config[REG_COLUMN_START].min_val;		
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1); 
	}
	if (nStart_x > cam_reg_config[REG_COLUMN_START].max_val) {
		error_msg = "The start_x variable value (%u) is bigger than the maximal legal value: %u", nStart_x , cam_reg_config[REG_COLUMN_START].max_val;		
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1); 
	}
	
	if (nStart_y < cam_reg_config[REG_ROW_START].min_val) {
		error_msg = "The start_y variable value (%u) is smaller than the minimal legal value: %u", nStart_y , cam_reg_config[REG_ROW_START].min_val;		
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1); 
	}
	if (nStart_y > cam_reg_config[REG_ROW_START].max_val) {
		error_msg = "The start_y variable value (%u) is bigger than the maximal legal value: %u", nStart_y , cam_reg_config[REG_ROW_START].max_val;		
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1); 

	}
	
	if (height != res_pic.height) {
		error_msg = "The captured picture does not have the same height as it is defined in the parameter";
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1);
	}	
	if (width != res_pic.width) {
		error_msg = "The captured picture does not have the same height as it is defined in the parameter";
		printf("%s %s:\nError: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_error(error_msg, __FUNCTION__);
		exit(-1);
	}
	
	return res_pic;
}


char lcv_config_write(unsigned int setting, unsigned short value)
{
	lcv_cam_reg_init();
	char warning_msg[256];
	
	if (0 <= setting && setting < cam_registers_cnt) {
		lcv_reg_config config = cam_reg_config[setting];
		
		if (config.min_val <= value && value <= config.max_val) {
			cam_reg_values[setting] = value;
			char log_entry[256];
			sprintf (log_entry, "Camera register Number %u was written to %u", config.addr, value);			
			lcv_log(log_entry);
			
			return TRUE;
		} else {
			sprintf(warning_msg,"Camera Register Number %u could not be written due to an illegal value: %u", config.addr, value);
			lcv_log_warning(warning_msg, __FUNCTION__);
			return ERROR_ILLEGAL_VALUE;
		}
	} else {
		sprintf(warning_msg,"Camera Register Number %u doesn't exist", setting);
		lcv_log_warning(warning_msg, __FUNCTION__);
		return ERROR_ILLEGAL_SETTING;
	}	
}

unsigned short lcv_config_read(unsigned int setting)
{
	lcv_cam_reg_init();
	char error_msg[256];
	
	if (0 <= setting && setting < cam_registers_cnt) {
		return cam_reg_values[setting];
	} else {
		sprintf(error_msg, "Camera Register Number %u does not exist", setting);
		//printf("%s %s:\nWarning: %s\n", "In Function", __FUNCTION__, error_msg);
		lcv_log_warning(error_msg, __FUNCTION__);
		return 0;
	}
}

char lcv_regs_to_default()
{
	int i;
	for (i=0; i<cam_registers_cnt; i++) {
		lcv_config_write(i, cam_reg_config[i].default_val);
	}
}

void lcv_reset_capture_frame()
{
	lcv_config_write(REG_COLUMN_START, cam_reg_config[REG_COLUMN_START].default_val);
	lcv_config_write(REG_ROW_START, cam_reg_config[REG_ROW_START].default_val);
	lcv_config_write(REG_WINDOW_WIDTH, cam_reg_config[REG_WINDOW_WIDTH].default_val);
	lcv_config_write(REG_WINDOW_HEIGHT, cam_reg_config[REG_WINDOW_HEIGHT].default_val);	
}

void lcv_cam_reg_init()
{
	int i;
	
	if (!cam_reg_initialized) {
		for (i=0; i<cam_registers_cnt; i++) {
			cam_reg_values[i] = cam_reg_config[i].default_val;
		}
		cam_reg_initialized = TRUE;
	}
}

void lcv_reg_buffering(const unsigned char enable) {
	//leer	
}
